﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace PortalCurriculo.Util.CustomControls.ListViewObjects
{
    public class ItemTemplate<T> : ITemplate
    {
        public ItemTemplate(List<Field> fields, object dataSource, List<ActionControl> actionControls)
        {
            Fields = fields;
            DataSource = (List<T>) dataSource;
            ActionControls = actionControls;
        }

        private List<T> DataSource { get; set; }
        private int Line { get; set; }
        private List<ActionControl> ActionControls { get; set; }
        public List<Field> Fields { get; set; }

        #region ITemplate Members

        public void InstantiateIn(Control container)
        {
            var row = new TableRow();

            object entity = DataSource[Line];

            foreach (Field field in Fields)
            {
                var cell = new TableCell(); // {AssociatedHeaderCellID = new[] {field.Name}};
                cell.Attributes.Add("for", field.DisplayName);
                cell.Controls.Add(new Label
                                      {
                                          Text =
                                              entity.GetType().GetProperty(field.Name).GetValue(entity, null).ToString(),
                                          ID = string.Concat("lbl", field.Name)
                                      });
                row.Cells.Add(cell);
            }

            if (ActionControls != null)
                row.Cells.Add(CreateActionControls(entity));

            container.Controls.Add(row);
            Line++;
        }

        #endregion

        private TableCell CreateActionControls(object entity)
        {
            var actionCell = new TableCell();

            foreach (ActionControl actionControl in ActionControls)
                actionCell.Controls.Add(ReplaceVariables(actionControl, entity));

            return actionCell;
        }

        private static Control ReplaceVariables(ActionControl actionControl, object entity)
        {
            List<PropertyInfo> properties = (from property in actionControl.Control.GetType().GetProperties()
                                             where property.GetValue(actionControl.Control, null) != null
                                                   &&
                                                   property.GetValue(actionControl.Control, null).ToString().Contains(
                                                       "[")
                                                   &&
                                                   property.GetValue(actionControl.Control, null).GetType().Equals(
                                                       typeof (string))
                                             select property).ToList();

            Control control = Clone(actionControl);

            foreach (PropertyInfo propertyInfo in properties)
            {
                string value = propertyInfo.GetValue(control, null).ToString();
                List<string> valueSplited = value.Split('[').ToList();

                List<string> variables = (from split in valueSplited
                                          where split.Contains("]")
                                          select split).ToList();

                propertyInfo.SetValue(control, Replace(variables, value, entity), null);
            }

            return control;
        }

        private static Control Clone(ActionControl control)
        {
            var controlCloned = (Control) Activator.CreateInstance(control.Control.GetType());

            foreach (PropertyInfo property in control.Control.GetType().GetProperties())
            {
                try
                {
                    if (!property.CanWrite || !property.CanRead) continue;

                    object value = property.GetValue(control.Control, null);
                    if (value == null || (value is string && string.IsNullOrEmpty(value.ToString()))) continue;

                    property.SetValue(controlCloned, value, null);
                }
                catch
                {
                }
            }

            if (control.Control.GetType().Equals(typeof (ImageButton)) && control.ClickImageButton != null)
                ((ImageButton) controlCloned).Click += control.ClickImageButton;
            else if (control.Control.GetType().Equals(typeof(Button)) && control.Click != null)
                ((Button) controlCloned).Click += control.Click;

            //foreach (var methodInfo in control.GetType().GetMethods())
            //{
            //    try
            //    {
            //        Delegate handler = Delegate.CreateDelegate(methodInfo.ReflectedType, control, methodInfo);
            //        //methodInfo.AddEventHandler(controlCloned, handler);

            //    }
            //    catch (Exception e)
            //    {

            //    }

            //}


            //foreach (var eventInfo in control.GetType().GetEvents())
            //{
            //    try
            //    {
            //        Delegate handler = Delegate.CreateDelegate(eventInfo.EventHandlerType, control.GetType().GetMethod("add_" + eventInfo.Name));
            //        eventInfo.AddEventHandler(controlCloned, handler);
            //    }
            //    catch (Exception e)
            //    {

            //    }

            //}

            return controlCloned;
        }

        //public static object Clone(object source)
        //{
        //    object newObject = Activator.CreateInstance(source.GetType());

        //    FieldInfo[] fields = newObject.GetType().GetFields();

        //    int i = 0;

        //    foreach (FieldInfo fi in source.GetType().GetFields())
        //    {
        //        Type ICloneType = fi.FieldType.
        //            GetInterface("ICloneable", true);

        //        if (ICloneType != null)
        //        {
        //            var IClone = (ICloneable)fi.GetValue(source);
        //            fields[i].SetValue(newObject, IClone.Clone());
        //        }
        //        else
        //            fields[i].SetValue(newObject, fi.GetValue(source));

        //        Type IEnumerableType = fi.FieldType.GetInterface
        //            ("IEnumerable", true);
        //        if (IEnumerableType != null)
        //        {
        //            var IEnum = (IEnumerable)fi.GetValue(source);

        //            Type IListType = fields[i].FieldType.GetInterface
        //                ("IList", true);
        //            Type IDicType = fields[i].FieldType.GetInterface
        //                ("IDictionary", true);

        //            int j = 0;
        //            if (IListType != null)
        //            {
        //                var list = (IList)fields[i].GetValue(newObject);

        //                foreach (object obj in IEnum)
        //                {
        //                    ICloneType = obj.GetType().
        //                        GetInterface("ICloneable", true);

        //                    if (ICloneType != null)
        //                    {
        //                        var clone = (ICloneable)obj;
        //                        list[j] = clone.Clone();
        //                    }

        //                    j++;
        //                }
        //            }
        //            else if (IDicType != null)
        //            {
        //                var dic = (IDictionary)fields[i].
        //                                            GetValue(newObject);
        //                j = 0;

        //                foreach (DictionaryEntry de in IEnum)
        //                {
        //                    ICloneType = de.Value.GetType().
        //                        GetInterface("ICloneable", true);

        //                    if (ICloneType != null)
        //                    {
        //                        var clone = (ICloneable)de.Value;
        //                        dic[de.Key] = clone.Clone();
        //                    }
        //                    j++;
        //                }
        //            }
        //        }
        //        i++;
        //    }
        //    return newObject;
        //}


        //public static T Clone<T>(T source)
        //{
        //    if (!typeof(T).IsSerializable)
        //    {
        //        throw new ArgumentException("The type must be serializable.", "source");
        //    }

        //    // Don't serialize a null object, simply return the default for that object
        //    if (Object.ReferenceEquals(source, null))
        //    {
        //        return default(T);
        //    }

        //    IFormatter formatter = new BinaryFormatter();
        //    Stream stream = new MemoryStream();
        //    using (stream)
        //    {
        //        formatter.Serialize(stream, source);
        //        stream.Seek(0, SeekOrigin.Begin);
        //        return (T)formatter.Deserialize(stream);
        //    }
        //}


        public static object DeepCopy(object obj)
        {
            MethodInfo memberwiseClone = typeof (object).GetMethod("MemberwiseClone",
                                                                   BindingFlags.Instance | BindingFlags.NonPublic);

            object newCopy = memberwiseClone.Invoke(obj, new object[0]);

            foreach (
                FieldInfo field in
                    newCopy.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
            {
                try
                {
                    if (!field.FieldType.IsPrimitive && field.FieldType != typeof (string))
                    {
                        object fieldCopy = DeepCopy(field.GetValue(newCopy));
                        field.SetValue(newCopy, fieldCopy);
                    }
                }
                catch
                {
                }
            }
            return newCopy;
        }


        private static string Replace(IEnumerable<string> variables, string value, object entity)
        {
            string replaced = value;

            foreach (string variable in variables)
            {
                try
                {
                    string variableToReplace = variable.Substring(0, variable.IndexOf(']'));

                    object field = entity.GetType().GetProperty(variableToReplace).GetValue(entity, null);

                    if (field == null) continue;

                    replaced = replaced.Replace(string.Concat("[", variableToReplace, "]"), field.ToString());
                }
                catch (Exception e)
                {
                }
            }

            return replaced;
        }
    }
}